<!DOCTYPE html>
<html lang="es">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Una referencia visual de Git</title>
  <link rel='stylesheet' type='text/css' href='visual-git-guide.css'>
  <script type="text/javascript" src='visual-git-guide.js'></script>
</head>
<body onload="replace_all_PNGs();">
  <h1 id="top">Una referencia visual de Git</h1>

  <div id="language-box">
    <a>Otros Idiomas:</a>
    <ul>
      <li><a href='index-de.html'>Deutsch</a></li>
      <li><a href='index-en.html'>English</a></li>
      <li class="selected">Español</li>
      <li><a href='index-fr.html'>Français</a></li>
      <li><a href='index-it.html'>Italiano</a></li>
      <li><a href='index-ja.html'>日本語</a></li>
      <li><a href='index-ko.html'>한국어</a></li>
      <li><a href='index-pl.html'>Polski</a></li>
      <li><a href='index-pt.html'>Português</a></li>
      <li><a href='index-ru.html'>Русский</a></li>
      <li><a href='index-sk.html'>Slovenčina</a></li>
      <li><a href='index-vi.html'>Tiếng Việt</a></li>
      <li><a href='index-zh-cn.html'>简体中文</a></li>
      <li><a href='index-zh-tw.html'>正體中文</a></li>
    </ul>
  </div>

  <p id="link-to-png">Si las imágenes no funcionan, puedes intentar la <a
    href="?no-svg">versión sin-SVG</a> de esta página.</p>

  <p id="link-to-svg">Las imágenes SVG se han desactivado.
  <a href="index.html">(volver a habilitar SVG)</a></p>

  <p>Esta página da una referencia breve y visual para los comandos más comunes
  en git.  Una vez que conozcas un poco sobre la forma de trabajo de git, este sitio puede fortalecer
  tu entendimiento.  Si estás interesado en cómo se creó este sitio, mirá mi
  <a href='http://github.com/MarkLodato/visual-git-guide'>repositorio de GitHub</a>.</p>

  <h2 id="contents">Contenidos</h2>
  <ol>
    <li><a href="#basic-usage">Uso Básico</a></li>
    <li><a href="#conventions">Convenciones</a></li>
    <li><a href="#commands-in-detail">Comandos en Detalle</a>
      <ol>
        <li><a href="#diff">Diff</a></li>
        <li><a href="#commit">Commit</a></li>
        <li><a href="#checkout">Checkout</a></li>
        <li><a href="#detached">Commiteando con un HEAD Detachado</a></li>
        <li><a href="#reset">Reset</a></li>
        <li><a href="#merge">Merge</a></li>
        <li><a href="#cherry-pick">Cherry Pick</a></li>
        <li><a href="#rebase">Rebase</a></li>
      </ol>
    </li>
    <li><a href="#technical-notes">Notas Técnicas</a></li>
  </ol>

  <h2 id="basic-usage">Uso Básico</h2>

  <div class="center"><img src='basic-usage.svg.png'></div>

  <p>Los cuatro comandos de arriba copian archivos entre el directorio de trabajo, el
  stage (también llamado index), y la historia (en la forma de commits).</p>

  <ul>

    <li><code>git add <em>archivos</em></code> copia <em>archivos</em> (en su
    estado actual) al stage.</li>

    <li><code>git commit</code> guarda una snapshot del stage como un commit.</li>

    <li><code>git reset -- <em>archivos</em></code> quita <em>archivos</em> de stage; esto es,
    que copia <em>archivos</em> del último commit al stage.  Usá este
    comando para "deshacer" un <code>git add <em>archivos</em></code>.  También podés usar
    <code>git reset</code> para quitar de stage todo lo que hayas agregado.</li>

    <li><code>git checkout -- <em>archivos</em></code> copia <em>archivos</em> desde 
    el stage al directorio de trabajo.  Usá esto para descartar los cambios locales.</li>

  </ul>

  <p>Podés usar <code>git reset -p</code>, <code>git checkout -p</code>, o
  <code>git add -p</code> en lugar de (o en combinación con) especificar archivos
  particulares para elegir interactivamente qué partes copiar.</p>

  <p>También es posible, además, saltarse el stage y hacer check-out de los archivos directamente
  desde los archivos de commit sin hacer primero el staging.</p>

  <div class="center"><img src='basic-usage-2.svg.png'></div>

  <ul>

    <li><code>git commit -a </code> es equivalente a utilizar el comando <tt>git add</tt> 
    en todos los archivos que hubo en el último commit, y correr luego el comando
    <tt>git commit</tt>.</li>

    <li><code>git commit <em>archivos</em></code> crea un nuevo commit incluyendo
    los contenidos del último commit, además de un snapshot de <em>archivos</em> tomado 
    del directorio de trabajo.  Adicionalmente, los <em>archivos</em> se copian 
    al stage.</li>

    <li><code>git checkout HEAD -- <em>archivos</em></code> copia <em>archivos</em> 
    del último commit a stage y al directorio de trabajo (a ambos)</li>

  </ul>

  <h2 id="conventions">Convenciones</h2>

  <p>En el resto del documento, usaremos gráficos de la siguiente forma.</p>

  <div class="center"><img src='conventions.svg.png'></div>

  <p>Los commits se muestran en verde como identificadores de 5 caracteres, y apuntan a sus
  padres. Los branch se muestran en naranja, y apuntan a un commit en particular.
  El branch actual se identifica por medio de una referencia especial
  <em>HEAD</em>, que es "adjuntada" al branch.  En esta imagen, se muestran
  los cinco últimos commits, con <em>ed489</em> siendo el más reciente.
  <em>master</em> (el branch actual) apunta a este commit, mientras que
  <em>maint</em> (otro branch) apunta a un antecesor del commit de <em>master</em>.</p>

  <h2 id="commands-in-detail">Comandos en Detalle</h2>

  <h3 id="diff">Diff</h3>

  <p>Hay varias formas de ver las diferencias entre commits. Debajo están
  algunos ejemplos comunes.  Cualquiera de esos comandos pueden tomar opcionalmente
  como argumento nombres de archivos que limiten las diferencias a los archivos nombrados.</p>

  <div class="center"><img src='diff.svg.png'></div>

  <h3 id="commit">Commit</h3>

  <p>Cuando commiteás, git crea un nuevo objeto de commit utilizando los archivos del
  stage y establece el padre al commit actual.  Entonces apunta el presente branch a
  este nuevo commit.  En la imagen debajo, el branch actual es <em>master</em>.
  Antes de que se ejecutase el comando, <em>master</em> apuntaba a
  <em>ed489</em>.  Luego, un nuevo commit, <em>f0cec</em>, se crea, con el
  padre <em>ed489</em>, y luego <em>master</em> se mueve al nuevo commit.</p>

  <div class="center"><img src='commit-master.svg.png'></div>

  <p>Este mismo proceso sucede aún cuando el branch actual es un ancestro de
  otro.  Debajo, un commit ocurre en el branch <em>maint</em>, el cual fue un
  ancestro de <em>master</em>, resultando en <em>1800b</em>.  Luego,
  <em>maint</em> no es más un ancestro de <em>master</em>.  Para reunir las dos
  historias, será necesario un <a href='#merge'>merge</a> (o <a href='#rebase'>rebase</a>).</p>

  <div class="center"><img src='commit-maint.svg.png'></div>

  <p>A veces pueden cometerse errores en un commit, pero son fáciles de corregir con
  <code>git commit --amend</code>.  Cuando usás este comando, git crea un nuevo commit
  con el mismo padre que el commit actual.  (El commit anterior será descartado
  si nada más lo referencia.)</p>

  <div class="center"><img src='commit-amend.svg.png'></div>

  <p>Un cuarto caso es commitear con un <a href="#detached">HEAD detachado</a>,
  como explicaremos después.</p>

  <h3 id="checkout">Checkout</h3>

  <p>El comando checkout se usa para copiar archivos de los commits (o desde stage)
  al directorio de trabajo, y para opcionalmente intercambiar branches.</p>

  <p>Cuando un nombre de archivo (y/o <code>-p</code>) se proporciona, git copia esos archivos
  desde el commit dado hacia stage y el directorio de trabajo. Por ejemplo,
  <code>git checkout HEAD~ foo.c</code> copia el archivo <code>foo.c</code>
  desde el commit llamado <em>HEAD~</em> (el padre del commit actual) al
  directorio de trabajo, y además lo pasa a stage.  (Si no se proporciona nombre de commit,
  los archivos se copiarán desde stage.)  Notá que el branch actual no se cambia.</p>

  <div class="center"><img src='checkout-files.svg.png'></div>

  <p>Cuando <em>not</em> se proporciona un nombre de archivo, pero la referencia es
  un branch (local), <em>HEAD</em> se mueve a ese branch (esto es, nosotros "cambiamos" ese
  branch), y entonces el stage y el directorio de trabajo se establecen para coincidir con
  los contenidos de ese commit.  Cualquier archivo que existe en el nuevo commit
  (<em>a47c3</em> debajo) se copia; cualquier archivo que exista en el anterior commit
  (<em>ed489</em>) pero no en el que está borrado; y cualquier archivo que exista
  será ignorado.</p>

  <div class="center"><img src='checkout-branch.svg.png'></div>

  <p>Cuando <em>not</em> se proporciona un nombre de archivo y la referencia <em>no</em> es
  un branch (local) &mdash; digamos, es un tag, un branch remoto, un identificador SHA-1, o
  algo como <em>master~3</em> &mdash; obtenemos un branch anónimo, llamado
  un <em>HEAD detachado</em>.  Esto es útil para saltar a través de la historia.
  Digamos que querés compilar la versión 1.6.6.1 de git.  Podés hacer <code>git checkout
    v1.6.6.1</code> (que es un tag, no un branch), compilar, instalar, y luego
  cambiar de nuevo a otro branch, digamos <code>git checkout master</code>.
  Sin embargo, commitear trabajos levemente diferentes con un HEAD detachado; esto es
  cubierto <a href="#detached">debajo</a>.</p>

  <div class="center"><img src='checkout-detached.svg.png'></div>

  <h3 id="detached">Commiteando con un HEAD detachado</h3>

  <p>Cuando el <em>HEAD</em> está detachado, commit trabaja como siempre, excepto
  que en un branch sin nombre.  (Podés pensar en esto como un branch anónimo.)</p>

  <div class="center"><img src='commit-detached.svg.png'></div>

  <p>Una vez que hacés un check-out de algo más, digamos <em>master</em>, el commit
  (supuestamente) no es referenciado más por nada, y se pierde. Notá que
  luego de ese comando, no hay nada referenciando <em>2eecb</em>.</p>

  <div class="center"><img src='checkout-after-detached.svg.png'></div>

  <p>Si, por otro lado, querés guardar este estado, podés crear un nuevo
  branch con nombre usando <code>git checkout -b <em>nombre</em></code>.</p>

  <div class="center"><img src='checkout-b-detached.svg.png'></div>

  <h3 id="reset">Reset</h3>

  <p>El comando reset mueve el branch actual a otra posición, y opcionalmente
  actualiza el stage y el directorio de trabajo.  Además se usa para
  copiar archivos desde los commits a stage sin tocar el directorio de trabajo.</p>

  <p>Si un commit se hace sin especificar nombres de archivos, el branch actual
  se mueve a ese commit, y luego el stage se actualiza para coincidir con ese commmit.
  Si se proporciona el parámetro <code>--hard</code> el directorio de trabajo también se
  actualiza. Si se proporciona el parámetro <code>--soft</code> ninguno se actualiza.</p>

  <div class="center"><img src='reset-commit.svg.png'></div>

  <p>Si no se proporciona un commit, por defecto se refiere a <em>HEAD</em>.  En este caso,
  el branch no se mueve, pero se pasa a stage (y opcionalmente al directorio de trabajo si
  se especifica el parámetro <code>--hard</code>) y reinicia a los contenidos del último commit.</p>

  <div class="center"><img src='reset.svg.png'></div>

  <p>Si se proporciona un nombre de archivo (y/o <code>-p</code>), entonces el comando trabaja
  en forma similar al <a href='#checkout'>checkout</a> con un nombre de archivo, excepto que solo
  el stage (y no el directorio de trabajo) se actualice.  (Además deberías especificar
  el commit del cual tomar los archivos, en lugar de <em>HEAD</em>.)</p>

  <div class="center"><img src='reset-files.svg.png'></div>

  <h3 id="merge">Merge</h3>

  <p>Un merge crea un nuevo commit que incorpora cambios de otros commit.
  Antes de mezclar, el stage debe coincidir con el commit actual.  El caso
  trivial es si el otro commit es un ancestro del commit actual, en cuyo
  caso no se hace nada adicional.  El siguiente más simple es si el commit actual
  es un ancestro del otro commit.  Esto resulta en una mezcla <em>fast-forward</em>.
  La referencia simplemente se mueve, y luego al nuevo commit se le hace check out.</p>

  <div class="center"><img src='merge-ff.svg.png'></div>

  <p>De otro modo, una mezcla "real" debe ocurrir.  Podés elegir otras estrategias,
  pero por defecto se realiza una mezcla "recursive", la cual básicamente toma el commit
  actual (<em>ed489</em> debajo), el otro commit (<em>33104</em>),
  y su ancestro común (<em>b325c</em>), y realiza una <a
    href='http://en.wikipedia.org/wiki/Three-way_merge'>mezcla de tres vías</a>.
  El resultado se guarda al directorio de trabajo y al stage, y luego ocurre
  un commit, con un padre adicional (<em>33104</em>) para el nuevo commit.
  </p>

  <div class="center"><img src='merge.svg.png'></div>

  <h3 id="cherry-pick">Cherry Pick</h3>

  <p>El comando cherry-pick "copia" un commit, creando un nuevo commit en el
  branch actual con el mismo mensaje y patch que otro commit.</p>

  <div class="center"><img src='cherry-pick.svg.png'></div>

  <h3 id="rebase">Rebase</h3>

  <p>Un rebase es una alternativa al <a href='#merge'>merge</a> para combinar
  múltiples branches.  Mientras que un merge crea un solo commit con dos
  padres, dejando una historia no lineal, un rebase reproduce los commits del
  branch actual en otro, dejando una historia lineal.  En esencia, esta es
  una forma automatizada de realizar muchas <a
    href='#cherry-pick'>cherry-pick</a> de una vez.</p>

  <div class="center"><img src='rebase.svg.png'></div>

  <p>El comando de arriba toma todos los commits que existen en <em>topic</em> pero
  no en <em>master</em> (nombrados <em>169a6</em> y <em>2c33a</em>), los reproduce
  dentro de <em>master</em>, y luego mueve el branch head al nuevo punto.
  Notá que los commits viejos serán recogidos por el recolector de basura si no son
  referenciados.</p>

  <p>Para limitar qué tanto va hacia atrás, usá la opción <code>--onto</code>.  El
  siguiente comando reproduce dentro de <em>master</em> el más reciente commit del
  branch actual desde <em>169a6</em> (exclusivo), concretamente <em>2c33a</em>.</p>

  <div class="center"><img src='rebase-onto.svg.png'></div>

  <p>Además existe <code>git rebase --interactive</code>, que permite hacer
  cosas más complicadas que simplemente reproducir commits, descartar, reordenar,
  modificar o juntar commits.  No hay una imagen obvia para graficar este concepto; ver <a
    href='http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html#_interactive_mode'>git-rebase(1)</a>
  para más detalles.</p>

  <h2 id="technical-notes">Notas Técnicas</h2>

  <p>Los contenidos de los archivos no se almacenan en realidad en el índice
  (<em>.git/index</em>) o en objetos commit.  En su lugar, cada archivo se almacena en
  el objeto database (<em>.git/objects</em>) como un <em>blob</em>, identificado
  por su hash SHA-1.  El archivo de índice lista los nombres de los archivos junto con el
  identificador del blob asociado, así como otros datos.  Para los commits,
  hay un tipo de dato adicional, un <em>tree</em>, también identificado por su hash.
  Los trees se corresponden con directorios del directorio de trabajo, y contienen
  una lista de trees y blobs que se corresponden a cada nombre de archivo dentro de ese
  directorio.  Cada commit almacena el identificador de su tree de alto nivel, el cual
  a su vez contiene todos los blobs y otros trees asociados con ese commit.</p>

  <p>Si hacés un commit usando un HEAD detachado, el último commit es el que se
  referencia por algo: el reflog para HEAD. Sin embargo, esto expirará
  luego de un tiempo, por eso el commit eventualmente será recogido por el garbage
  collector, de forma similar a los commits descartados con <code>git commit --amend</code>
  o <code>git rebase</code>.</p>

  <hr>

  <p>Copyright &copy; 2010,
    <a href='mailto:lodatom@gmail.com'>Mark Lodato</a>.
  Spanish translation &copy; 2012,
    <a href='http://www.delucas.com.ar'>Lucas Videla</a>.
  </p>

  <p><a rel="license"
    href="https://creativecommons.org/licenses/by-nc-sa/3.0/us/deed.es"><img alt=""
    src="https://i.creativecommons.org/l/by-nc-sa/3.0/us/80x15.png"></a>
  Este trabajo está licenciado bajo una <a rel="license"
    href="https://creativecommons.org/licenses/by-nc-sa/3.0/us/deed.es">Creative
    Commons Attribution-Noncommercial-Share Alike 3.0 United States
    License</a>.</p>

  <p><a href='translate-en.html'>¿Querés traducirlo a otro idioma?</a></p>

</body>
</html>
